package leducHoldem.Calculator;

import java.util.LinkedList;

import leducHoldem.Data.Move;
import leducHoldem.misc.CFRInformationSet;

public class LeducHoldemValueCalculator extends ValueCalculator {

	@Override
	public void updateValues(int iteration) {
		updateValues("J", iteration);
		updateValues("Q", iteration);
		updateValues("K", iteration);
	}

	/**
	 * Updates values of available moves in every information set
	 * 
	 * @param id
	 * @return
	 */
	private float[] updateValues(String id, int iteration) {

		CFRInformationSet set = gameTree.get(id);

		if (set.isTerminal() != 0) {

			if (set.getLastMove().action.equals("f")) {
				return getValuesForFold(set);
			}

			return getValuesForTerminal(set);
		}

		updateSet(id, iteration, set);

		return getValuesToPropageteUp(set);

	}

	private void updateSet(String id, int iteration, CFRInformationSet set) {

		set.resetValuesForCards();
		set.resetValues();

		int moveCounter = 0;

		for (Move move : set.getMoves()) {
			updateSetValuesForMove(id, iteration, set, moveCounter, move);
			moveCounter++;
		}

		set.computeValues();
	}

	private void updateSetValuesForMove(String id, int iteration, CFRInformationSet set, int moveCounter, Move move) {
		
		int childCounter = 0;
		
		if(set.getCurrentPlayer() == 3) {
//			set.addValuesForCard(moveCounter, updateValues(getIdWithMove(move, id), iteration));!!!!!!
			set.addValuesForMove(moveCounter, updateValues(getIdWithMove(move, id), iteration));
			return;
		}
		
		if(dealer.isChanceSet(getIdWithMove(move, id)) && set.getCurrentPlayer() == 1) {
			set.addValuesForMove(moveCounter, updateValues(getIdWithMove(move, id), iteration));
			return;
		}

		for (String childId : generateChildrenIdsForMove(move, id)) {

			float[] valuesFromChild = updateValues(childId, iteration);

			if (dealer.isTerminal(childId)) {
				set.addValuesForMove(moveCounter, valuesFromChild);
			} else {				
				set.addValuesForMoveAndCard(moveCounter, childCounter, getValueForCard(valuesFromChild, set));
			}

			childCounter++;
		}
	}

	private float[] getValuesToPropageteUp(CFRInformationSet set) {

		float[] values = new float[3];

		for (int j = 0; j < 3; j++) {
			for (int i = 0; i < set.getStrategy().length; i++) {
				values[j] += set.getValuesOnIndex(j)[i] * set.getStrategy()[i];
			}
		}

		return values;
	}

	private float[] getValuesForTerminal(CFRInformationSet set) {

		float[] values = new float[3];

		for (int i = 0; i < set.getProbabilities().length; i++) {

			Move[] tempCards = new Move[] { set.getCard(), new Move((byte) (i + 1)) };

			if (dealer.hasPlayerOneWon(tempCards[set.getCurrentPlayer() - 1], tempCards[2 - set.getCurrentPlayer()], set.getTable())) {
				values[i] = set.getPot();
			} else if (dealer.hasPlayerTwoWon(tempCards[set.getCurrentPlayer() - 1], tempCards[2 - set.getCurrentPlayer()], set.getTable())) {
				values[i] = -set.getPot();
			}
		}

		return values;
	}

	private float[] getValuesForFold(CFRInformationSet set) {

		float[] valuesToPropagate = new float[3];

		for (int i = 0; i < valuesToPropagate.length; i++) {
			valuesToPropagate[i] = set.isTerminal() == 2 ? -set.getPot() : set.getPot();
		}

		return valuesToPropagate;
	}

	private float getValueForCard(float[] valuesFromChild, CFRInformationSet set) {
		return valuesFromChild.length == 1 ? valuesFromChild[0] : valuesFromChild[set.getCard().value - 1];
	}

	public LinkedList<String> generateChildrenIdsForMove(Move move, String id) {

		LinkedList<String> children = new LinkedList<String>();
		String idWithMove = getIdWithMove(move, id);

		if (dealer.isTerminal(idWithMove)) {

			children.add(idWithMove);

			return children;
		}

		for (Move card : dealer.getCardTypes()) {
			children.add(getIdWithMoveAndCard(move, id, card));
		}

		return children;
	}

	private String getIdWithMoveAndCard(Move move, String id, Move card) {

		StringBuilder builder = new StringBuilder();

		builder.append(card);
		builder.append(id.substring(1));
		builder.append(".");
		builder.append(move);

		return builder.toString();
	}

	private String getIdWithMove(Move move, String id) {

		StringBuilder builder = new StringBuilder();

		builder.append(id);
		builder.append(".");
		builder.append(move);

		return builder.toString();
	}

}
